<template>
  <!-- 需求表 -->
  <div ref="tableContainer" class='tableContainer'>
    <div class="toolbar">
      <div v-for="item in toolbar" :key="item.key" class="toolbarDiv">
        <div
          :class="`toolbarItem ${item.type} ${item.type ==='button' && item.name !== 'selectRequirement' && !selectedRow ? 'disabled': ''}`"
          :style="{width:item.width}"
          @click="item.type === 'button' &&  ( !!selectedRow  ||item.name === 'selectRequirement') && item.fn()">
          <a-dropdown v-if="item.type === 'checkList'" class="_dropdown" :trigger="['click']">
          
            <div class="itemContent"><div :class="`icon icon_${item.name}`" ></div><div style="margin-right: 2px">{{item.des}}</div><a-icon  type="down" /></div>
            <a-menu slot="overlay" class="checkListMenu">
              <a-checkbox-group
                v-if="AllColumnIds.length !== 0"
                :options="AllColumnIds"
                :value="selectedColumnIds"
                @change="onChange">
                <span slot="label" slot-scope="{ label }" style="font-size: 12px">{{label}}</span>
              </a-checkbox-group>
            </a-menu>
          </a-dropdown>
          <a-dropdown
            v-else-if="item.type === 'buttonList'"
            class="_dropdown"
            :trigger="['click']"
            :disabled="item.key === 'iconexport' && originData.length <= 0"
            :class="{disabled: item.key === 'iconexport' && originData.length <= 0}">
       
            <div class="itemContent"><div :class="`icon icon_${item.name}`" ></div><div class="des" style="margin-right: 2px">{{item.des}}</div><a-icon  type="down" /></div>
            <a-menu slot="overlay" class="buttonListMenu">
              <a-menu-item v-for="subItem in item.children" :key="subItem.key" :disabled="subItem.disabled && !selectedRow"  @click="subItem.fn">
                {{subItem.name}}
              </a-menu-item>
            </a-menu>
          </a-dropdown>
          <div v-else>
            <div :class="`icon icon_${item.name} `" ></div>
          </div>
          <div v-if="item.type === 'button'" class="des">{{item.des}}</div>
        </div>
        <div v-if="item.line" class="iconbarline">
          <img src="statics/icons/app/barline.svg">
        </div>
      </div>
    </div>
    <div class='searchBar' @click="clickOuthandler">
      <span>搜索</span>
      <a-select v-model="selectedColumn" class="_select" >
        <a-select-option value="all">
          全部字段
        </a-select-option>
        <template v-for="option in selectData" >
          <a-select-option :key="option.key" :v-if="option.key !== 'key'" :value="option.key">
            {{ option.name }}
          </a-select-option>
        </template>

      </a-select>
      <a-input-search
        v-model="searchValue"
        enter-button
        class="_input"
        placeholder="请输入关键字"
        @search="onSearch">
        <a-icon
          v-show=" searchValue !== '' "
          slot="suffix"
          type="close-circle"
          theme="filled"
          @click="clearSearchValue"
        />
      </a-input-search>
      <span v-show="searchResultVisible" class="searchResult">共{{ count }}处搜索结果</span>

      <img
        v-show="searchResultVisible"
        :style="previousClass"
        src="statics/icons/table/arrowup.svg"
        @mouseenter="arrowUpIn"
        @mouseout="arrowUpOut"
        @click="arrowUpClick">
      <img
        v-show="searchResultVisible"
        :style="nextClass"
        src="statics/icons/table/arrowdown.svg"
        @mouseenter="arrowDownIn"
        @mouseout="arrowDownOut"
        @click="arrowDownClick">
      <div v-show="previousTipVisible" class="previousTip">
        <div class="triangle"></div>
        <div class="rectangle">上一处</div>
      </div>
      <div v-show="nextTipVisible" class="nextTip">
        <div class="triangle"></div>
        <div class="rectangle">下一处</div>
      </div>
    </div>
    <div
      ref="table"
      class='_table'
      @click="clickOuthandler"
      @drop="dragHandler"
      @dragover="handleTreeDragMouseover">
      <a-table
        :columns="tableColums"
        :data-source="originData"
        :components="components"
        :pagination="false"
        :customRow="customRow"
        :customHeaderRow="customHeaderRow"
        :rowClassName="rowClassName"
        :expandIconColumnIndex="expandIconColumnIndex"
        :defaultExpandedRowKeys="defaultExpandedRowKeys"
        :locale="tablenodata"
        :expandIcon="changeExpandIcon"
        :indentSize="indentSize"
        rowKey='modelElementId'
        bordered
        size="small"
        @expandedRowsChange="expandedRowsChange"
      >
        <template slot="empty">
          <p>暂无数据</p>
        </template>
        <template v-for="(item,i) in tableColums" #[item.key]="text, record, index">
          <span v-if="item.dataIndex === 'ReqId' || item.dataIndex === 'key'" :key="item.id">{{text}}</span>
          <div
            v-else
            :key="item.key"
            :class="`textCell ${item.key}`"
          >

            <template v-if="item.editType ==='input' || item.editType ==='textarea'">
              <img  v-if="!record[`${item.enName}Editable`] && item.dataIndex === 'Name'" src="statics/images/sysml/Requirement.svg"/>
              <div   v-if="!record[`${item.enName}Editable`]" class="div_input">{{text}}<a-icon type='edit' @click.stop="showTextAreaModal(text, record, index,{propsName:item.key,editType:item.editType})"></a-icon>
              </div>
              <a-input
                v-else
                :key="item.key"
                ref="input"
                :value="text"
                @blur="(e)=>contentConfirm(e,record,index,{editType:item.key,propsName:item.enName})"
                @pressEnter="(e)=>contentConfirm(e,record,index,{editType:item.key,propsName:item.enName})"></a-input>
            </template>
            <template v-if="item.editType === 'tree-muti-select'">
              <template v-for="value in text">
                <div :key="value.id">
                  <img  v-if="value.icon" style="margin-top:-3px" :src="value.icon"/>
                  <span>{{value.name}}</span>
                </div>
              </template>
              <img
                v-show="selectIndex && selectIndex[0] === i && selectedRowIndex === record.model.cells[0].value"
                class="iconAdd addModal"
                style="height:12px;width:12px;cursor:pointer;"
                src='statics/icons/app/iconadd3.png'
                @click.stop="()=>handleMutiSelect(record)">
            </template>

            <template  v-else-if="item.editType === 'tree-single-select'">
              <span style="display: inline-block; line-height: 16px; width: 100%; height: 16px">
                <img v-if="text && text.icon" style="margin-top:-3px" :src="text && text.icon"/>
                <span v-if="text">{{text.name}}</span>
                <img
                  v-show="selectIndex && selectIndex[0] === i && selectedRowIndex === record.model.cells[0].value"
                  style="height: 12px; width: 12px;cursor:pointer;"
                  src="statics/icons/app/iconmore.png"
                  class="addModal"
                  @click.stop="()=>handleSingleSelect(record, index)"
                />
              </span>
              
            </template>

          </div>
        </template>
      </a-table>
    </div>
  </div>
</template>
<script>
import Vue from 'vue';
import VueDraggableResizable from 'vue-draggable-resizable';
import { treeForEach, storage, getUniqueName } from 'src/util/common';
import { textareaModal } from './Modal/TextArea';
import { ContextMenu } from 'components/common/ContextMenu/index';
import { menuConfig } from './menuConfig';
import { selectMutiple } from 'components/Attribute/modals/SelectMutiple.vue';
import { selectValue } from 'components/Attribute/modals/SelectValue.vue';
import { SysMLUtilHelper } from 'src/api/sysml-imports';
import treeUtil from '.././ModelTree/treeUtil';
import tableUtil from '.././RequirementTable/tableUtil';
import LocalFile from 'src/util/localFile/index';
import { chooseElement } from '../common/ChooseElement.vue';
import XLSX from 'xlsx';
import { graphHelper } from 'src/api/GraphHelper';
import { PropertyUtil } from 'src/components/Attribute/comps/PropertyUtil.ts';
import globalConfig from 'src/util/Global';
import { GraphNodeUtil } from '@/pages/mxgraph/GraphNodeUtil';
import { actions } from 'src/pages/mxgraph/Actions';

function getUniqueTitle(array, type, number = 1) {
  let title = `未命名${type}(${number})`;
  if (array.every((element) => element.title !== title)) {
    return title;
  } else {
    return getUniqueTitle(array, type, number + 1);
  }
}

Vue.component('vue-draggable-resizable', VueDraggableResizable);
const COLUMNSWIDTH = {
  Name: 184,
  Text: 544,
};
export default {
  name: 'requirement-table',
  directives: {
    focus: {
      //// 指令的定义
      inserted: function (el) {
        el.focus();
      },
    },
  },
  props: {
    tableId: String,
    visible: Boolean,
  },
  data() {
    const components = {
      header: {
        cell: (h, props, children) => {
          const { key, ...restProps } = props;
          const col = this.columns.find((col) => {
            const k = col.dataIndex || col.key;
            return k === key;
          });
          if (!col || !col.width) {
            return h('th', { ...restProps }, [...children]);
          }

          const dragProps = {
            key: col.dataIndex || col.key,
            class: 'table-draggable-handle',
            attrs: {
              w: 10,
              x: col.width,
              z: 1,
              axis: 'x',
              draggable: true,
              resizable: false,
            },
            on: {
              dragging: (x, y) => {
                if (col.key === 'key') {
                  col.width = Math.max(x, 26);
                } else if (col.name.length === 2) {
                  col.width = Math.max(x, 48);
                } else if (col.name.length === 3) {
                  col.width = col.width = Math.max(x, 50);
                } else {
                  col.width = col.width = Math.max(x, 74);
                }
              },
            },
          };

          const drag = h('vue-draggable-resizable', { ...dragProps });

          return h(
            'th',
            {
              ...restProps,
              class: {
                'resize-table-th': true,
                headerRowCell:
									this.selectIndex === 'all' ||
									this.selectIndex.includes(col.index),
                contentCell: col.key === 'Text',
              },
            },
            [...children, drag]
          );
        },
      },
    };

    return {
      indentSize: 0,
      scale: 100,
      searchValue: '', //// 搜索关键词
      selectedColumn: 'all', //// 搜索栏的下拉
      originData: [], //// 表格的数据源
      selectElements: [], //// 选中的dom节点,用来做点击效果
      searchElements: [], //// 搜索到的dom节点,用来做搜索高亮
      selectedRow: null, //// 当前选中的行数据
      tableData: [], //// 从后端获取的表格数据,需要转换成originData
      //// tablenodata:{
      ////   emptyText:()=>(
      ////   <div><div><img src="/static/images/utils/nodata.png" width="200" /></div><div>暂无数据</div></div>
      //// )},
      tablenodata: {
        emptyText: '暂无数据'
      },
      columns: [], //// 表格的colums 配置
      components, //// 为了实现可拖动表头
      textareaVisible: true, //// 文本编辑弹窗是否可见
      AllColumnIds: [], //// 所有的表头字段
      selectedColumnIds: [], //// 已选中的表头字段
      selectedRowIndex: '', //// 当前选中行的序号
      selectIndex: [], //// 当前选中的列的index 如果点击的是第一列 则是all 如果是后面的列,为一个子元素从1开始的数组
      defaultExpandedRowKeys: [], //// 表格受控得展开树形数据
      count: 0, //// 搜索结果数量
      searchResultVisible: false, //// 搜索结果可见性
      previousTipVisible: false, //// 搜索结果上一个按钮可见性
      nextTipVisible: false, //// 搜索结果下一个按钮可见性
      previousOpacity: '', //// 搜索结果上一个按钮透明度
      nextOpacity: '', //// 搜索结果下一个按钮透明度
      events: {
        'model-update': this.updateTable,
        'model-delete': this.updateTable,
      },
      toolbar: [
        {
          name: 'recall',
          key: 'recall',
          icon: 'recall',
          type: 'button',
          tips: '重做',
          fn: this.handleUndo,
          des: '',
          width: '20px',
        },
        {
          name: 'redo',
          key: 'redo',
          icon: 'redo',
          type: 'button',
          tips: '撤销',
          des: '',
          width: '20px',
          fn: this.handleRedo,
        },
        {
          name: 'showModelPosition',
          key: 'showModelPosition',
          icon: 'icontreelocation',
          type: 'button',
          tips: '树上高亮',
          fn: this.showModelPostion,
          des: '',
          width: '20px',
        },
        {
          name: 'iconMoveup',
          key: 'iconMoveup',
          icon: 'iconMoveup',
          type: 'button',
          tips: '上移',
          des: '',
          width: '20px',
          fn: () => this.upMove(),
        },
        {
          name: 'iconMovedown',
          key: 'iconMovedown',
          icon: 'iconMovedown',
          type: 'button',
          tips: '下移',
          des: '',
          width: '20px',
          fn: () => this.downMove(),
        },
        {
          name: 'deleteRequirement',
          key: 'deleteRequirement',
          icon: 'deleteRequirement',
          type: 'button',
          tips: '删除',
          fn: () => this.deleteRequirement(),
          des: '',
          width: '20px',
          line: true,
        },
        {
          name: 'removeFromTable',
          key: 'removeFromTable',
          icon: 'removeFromTable',
          type: 'button',
          tips: '移出',
          fn: () => this.removeFromTable(),
          des: '移出',
          width: '56px',
          line: true,
        },
        {
          name: 'addRequirement',
          key: 'addRequirement',
          icon: 'addRequirement',
          type: 'buttonList',
          tips: '新建需求',
          des: '新建需求',
          line: true,
          width: '90px',
          children: [
            {
              name: '新建子级',
              fn: (e) => this.addRequirement(e, { level: 'child' }),
              disabled: true,
            },
            {
              name: '新建同级',
              fn: (e) => this.addRequirement(e, { level: 'same' }),
              disabled: true,
            },
            {
              name: '尾部新建',
              fn: (e) => this.addRequirement(e, { level: 'tail' }),
            }
          ],
        },
        {
          name: 'selectRequirement',
          key: 'selectRequirement',
          icon: 'selectRequirement',
          type: 'button',
          tips: '选择已有需求',
          fn: () => this.selectRequirement(),
          des: '选择已有需求',
          width: '100px',
          line: true,
        },
        {
          name: 'iconLegend',
          key: 'iconLegend',
          icon: 'iconLegend',
          type: 'button',
          tips: '图例',
          des: '图例',
          width: '50px',
          line: true,
          fn: () => this.legendClick(),
        },
        {
          name: 'requirementField',
          key: 'requirementField',
          icon: 'requirementField',
          type: 'checkList',
          tips: '显示字段',
          des: '显示字段',
          width: '90px',
          line: true,
        },
        //// {
        ////   name: 'iconleadin',
        ////   key: 'iconleadin',
        ////   icon: 'iconleadin',
        ////   type: 'buttonList',
        ////   des: '导入',
        ////   tips: '导入',
        ////   line: true,
        ////   width: '62px',
        ////   children: [
        ////     {
        ////       name: 'Excel',
        ////       fn: (e) => this.importRequirementTableExcel(),
        ////     },
        ////     {
        ////       name: 'ReqIF',
        ////       fn: (e) => this.importRequirementTableReqif(),
        ////       disabled: false,
        ////     }
        ////     //// {
        ////     ////   name: '新建同级',
        ////     ////   fn: (e) => this.addRequirement(e, { level: 'same' }),
        ////     ////   disabled: true
        ////     //// }
        ////   ],
        //// },
        {
          name: 'iconexport',
          key: 'iconexport',
          icon: 'iconexport',
          type: 'buttonList',
          des: '导出',
          tips: '导出',
          line: true,
          width: '62px',
          children: [
            {
              name: 'Excel',
              fn: (e) => this.exportRequireTableExcel(),
            },
            {
              name: 'ReqIF',
              fn: (e) => this.exportRequirementTableReqif(),
              disabled: false,
            }
          ],
        }
      ],
    };
  },
  computed: {
    tableColums() {
      let cl = [];
      if (this.tableData.length === 0) {
        return cl;
      }
      cl.push(this.columns[0]);
      //// console.log(this.columns[4], this.tableData.visibleColumns[4]);
      this.tableData.visibleColumns.forEach((item, index) => {
        let config = this.columns.find((value) => value.key === item.key);
        const newConfig = { ...config, editType: item.editType };
        //// if (newConfig.editType === 'tree-muti-select') {
        ////   newConfig.editType = 'tree-single-select'; //// 全部改为单选
        //// }
        cl.push(newConfig);
      });

      return cl;
    },
    //// 表格中 展开'➕'的位置
    expandIconColumnIndex() {
      return this.tableColums.findIndex((value) => value.key === 'ReqId');
    },

    selectData() {
      return this.tableData.visibleColumns;
    },

    previousClass() {
      return { opacity: this.previousOpacity };
    },

    nextClass() {
      return { opacity: this.nextOpacity };
    },
  },
  watch: {
    //// tableData(params) {
    ////   this.originData = this.formatTableData();
    //// },
    visible(boo) {
      if (boo) {
        this.count = 0;
        this.updateTable();
      }
    },
  },
  beforeMount() {
    this.updateTable();
    let columnIds = tableUtil.getAllColumn(this.tableId).columnIds;
    console.log('columnId', tableUtil.getAllColumn(this.tableId).columnIds);
    this.AllColumnIds = columnIds.map((item) => {
      return { label: item.name, value: item.key };
    });
    let cl = [];
    cl.push({
      title: '#',
      dataIndex: 'key',
      key: 'key',
      editType: 'key',
      index: 0,
      width: 48,
      scopedSlots: { customRender: 'key' },
      customCell: (record, rowIndex) =>
        this.customCell(record, rowIndex, { editType: 'key' }),
    });
    columnIds.forEach((item, index) => {
      const config = {
        index: index + 1,
        scopedSlots: { customRender: item.key },
        key: item.key,
        dataIndex: item.key,
        title: item.name,
        width: COLUMNSWIDTH[item.key] || 164,
        ellipsis: true,
        customCell: (record, rowIndex) => {
          //// if (item.editType === 'tree-muti-select') {
          ////   item.editType = 'tree-single-select'; //// 全部改为单选
          //// }
          return this.customCell(record, rowIndex, {
            editType: item.editType,
            propsName: item.enName,
          });
        },
        ...item,
      };
      //// if (item.key === 'Text'){
      ////   Reflect.deleteProperty(config, 'width');
      //// }
      cl.push({ ...config });
    });
    this.columns = cl;
  },
  mounted() {
    this.$bus.onBatch(this.events);
  },
  beforeDestroy() {
    this.$bus.offBatch(this.events);
  },

  methods: {
    expandedRowsChange(expandedRows) {
      console.log('expandedRows', expandedRows);
      this.defaultExpandedRowKeys = expandedRows;
    },
    handleUndo() {
      console.log('undo');
      app.$messageBox.warn({
      //// id: 100,
        text: '功能开发中，敬请期待',
        title: '试用版'
      });
    },
    handleRedo() {
      app.$messageBox.warn({
      //// id: 100,
        text: '功能开发中，敬请期待',
        title: '试用版'
      });
    },
    updateTable(newGraphNode) {
      if (!this.visible) {
        return;
      }
      const diagramNode = graphHelper.getGraphNodeById(this.tableId, app.activeProjectId);
      const tableData = tableUtil.getData(this.tableId, diagramNode);
      console.log('tableData', tableData);
      const visibleColumnsKeys = diagramNode.getVisibleColumns();

      //// 将visibleColumnsKeys的值以键名放入visibleColumnsKeysObj中
      const visibleColumnsKeysObj = {};
      visibleColumnsKeys.forEach(item => visibleColumnsKeysObj[item] = true);

      //// 根据visibleColumnsKeysObj过滤AllColumn
      tableData.visibleColumns = tableUtil.getAllColumn(this.tableId).columnIds.filter(item => visibleColumnsKeysObj[item.key]);
      this.selectedColumnIds = tableData.visibleColumns.map((item) => {
        return item.key;
      });
      const formatTableData = this.setCell(diagramNode, newGraphNode, tableData.visibleColumns);
      this.tableData = tableData;
      this.originData = formatTableData;
    },

    setCell(rootNode, newGraphNode, visibleColumns) {
      console.log('setCell');
      const rows = rootNode.umlDiagramFrame.children;
      if (!rootNode.propertyKeysObj && rows.length > 0) {
        this.initProperty(rows[0].container, rootNode);
      }
      const propertiesIndex = [];
      let propertiesObj = rootNode.propertyKeysObj;
      const unNamedNodes = [];
      const unNamedNodesObj = {}; //// 存储未命名的title
      const formatTableData = []; //// 格式化后的table数据，用于展示

      let index = 1;
      let cell = {
        icon: "",
        inEdit: false,
        name: "#",
        order: 0,
        value: '',
        valueType: undefined
      };
      this.searchTree(rows, 0, (row, depth) => {
        if (row.container && row.container.properties && row.container.properties.size === 0) {
          this.initProperty(row.container, rootNode);
          propertiesObj = rootNode.propertyKeysObj;
        }
        const cells = [];
        const currentObj = {};
        const graphNode = row.container;
        const properties = graphNode.properties.toArray();
        const cacheCell = { ...cell };
        cacheCell.value = index;
        cells.push(cacheCell);
        if (depth === 0) {
          formatTableData.push(currentObj);
        } else {
          row.owner.tableData.children.push(currentObj);
        }
        this.selectedColumnIds.forEach((key, i) => {
          let formatKey = '';
          switch (key) {
            case 'ReqId':
              formatKey = 'Id';
              break;
            case 'Name':
              formatKey = '名称';
              break;
            case 'Owner':
              formatKey = '所有者';
              break;
            default:
              formatKey = key;
          }

          const propertyIndex = propertiesObj[formatKey];
          const currentproperty = properties[propertyIndex];
          const value = PropertyUtil.getNodePropertyValue(graphNode, currentproperty);
          const name = PropertyUtil.getNodePropertyValue(graphNode, properties[propertiesObj['名称']]);
          const currentCell = { ...cell };
          currentCell.value = value;
          currentCell.order = i + 1;
          currentCell.name = formatKey;
          //// 初始化名称
          if (newGraphNode && newGraphNode.tagName === 'Class') {
            //// if (name && name.startsWith('未命名')) {
            ////   unNamedNodes.push(graphNode);
            ////   unNamedNodesObj[name] = true;
            //// }
            if (newGraphNode.id === graphNode.id) {
              depth !== 0 &&
              !this.defaultExpandedRowKeys.includes(row.owner.container.id) &&
              this.defaultExpandedRowKeys.push(row.owner.container.id);
            }
          }

          switch (formatKey) {
            case 'Text':
              currentCell.value = currentCell.valueEdit = value;
              break;
            default:
              formatKey = key;
          }
          if (currentCell.value instanceof Object && !currentCell.value.icon) {
            currentCell.value.icon = currentCell.icon;
          }
          if (visibleColumns[i]) {
            currentObj[visibleColumns[i].key] = value;
          }
          cells.push(currentCell);
        });
        index++;
        row.cells = cells;
        if (row.children && row.children.length > 0) {
          currentObj.children = [];
        }
        currentObj.index = this.getRowIndex(row);
        currentObj.moreBtnCondition = row.umlDiagramElement.moreBtnCondition;
        currentObj.key = row.cells[0].value;
        currentObj.id = row.id; //// id是真正的key
        currentObj.model = row;
        currentObj.modelElementId = row.container.id;
        currentObj.depth = depth;
        row.tableData = currentObj; //// 建立与tabledata的连接
        return row.children;
      });
      //// if (newGraphNode && newGraphNode.tagName === 'Class') {
      ////   const name = this.getName(1, unNamedNodesObj);
      ////   const properties = newGraphNode.properties.toArray();
      ////   //// TODO
      ////   PropertyUtil.updateRow(name, properties[propertiesObj['名称']], newGraphNode);
      ////   //// 更新name
      ////   this.selectedColumnIds.forEach((item, index) => {
      ////     if (item === 'Name') {
      ////       newGraphNode.rowElement.cells[index + 1].value = name;
      ////       newGraphNode.rowElement.cells[index + 1].valueEdit = name;
      ////       newGraphNode.rowElement.tableData.Name = name;
      ////     }
      ////   });
      //// }
      return formatTableData;
    },

    //// 获取同层row的次序
    getRowIndex (row) {
      const currentId = row.id;
      const parentRow = row.owner;
      const parentRowChildren = row.owner.children;
      let index = 0;
      for (let i = 0; i < parentRowChildren.length; i++) {
        const currentRow = parentRowChildren[i];
        const id = currentRow.id;
        if (currentId === id) {
          index = i;
          break;
        }
      }
      return index;
    },

    getName(number, obj) {
      let title = `未命名需求(${number})`;
      if (number === 0) {
        title = '未命名需求';
      }
      if (obj[title]) {
        return this.getName(number + 1, obj);
      } else {
        return title;
      }
    },

    /**
     * @param {array} node
     * @param {function} callback
     * @returns {void}
     */
    searchTree(node, depth, callback) {
      if (Array.isArray(node)) {
        node.forEach(child => this.searchTree(child, depth, callback));
      } else {
        const children = callback(node, depth);
        depth++;
        if (children) {
          this.searchTree(children, depth, callback);
        }
      }
    },

    formatTableData(rows = this.tableData.visibleRows, depth = 0) {
      return rows.map((row, i) => {
        let obj = {};
        row.cells.forEach((item, index) => {
          const children = row.parent.children;
          if (index === 0) return; //// 第一列是序号列  在col中不出现 特殊处理
          if (item.value instanceof Object && !item.value.icon) {
            item.value.icon = item.icon;
          }
          if (children && children.length !== 0) {
            obj.children = this.formatTableData(children, depth + 1);
          }
          if (this.tableData.visibleColumns[index - 1]) {
            obj[this.tableData.visibleColumns[index - 1].key] = item.value;
          }
        });
        depth !== 0 &&
					!this.defaultExpandedRowKeys.includes(row.id) &&
					this.defaultExpandedRowKeys.push(row.id);
        obj.index = i;
        obj.moreBtnCondition = rows[i].moreBtnCondition;
        obj.key = row.cells[0].value;
        obj.id = row.id; //// id是真正的key
        obj.model = row;
        obj.modelElementId = row.modelElementIds.toArray()[0];
        obj.depth = depth;
        return obj;
      });
    },
    rowClassName: function (record) {
      return 'customRow';
    },

    customCell: function (record, rowIndex, { editType, propsName }) {
      let cellConfig = {
        key: {
          on: {
            click: (e) => this.selectAllCell(e, record, rowIndex),
            contextmenu: (e) => {
              this.selectAllCell(e, record, rowIndex);
            },
          },
        },
        textarea: {
          on: {
            dblclick: (e) =>
              this.contentDbclick(record, rowIndex, {
                editType,
                propsName,
              }),
          },
        },
        input: {
          on: {
            dblclick: (e) =>
              this.contentDbclick(record, rowIndex, {
                editType,
                propsName,
              }),
          },
        },
        'tree-single-select': {
          on: {
            dblclick: (e) => this.handleSingleSelect(record, rowIndex),
          },
        },
        'tree-muti-select': {
          on: {
            dblclick: (e) => this.handleMutiSelect(record),
          },
        },
      };
      let config = cellConfig[editType]; //// 单元格
      return config;
    },
    customHeaderRow: function (record, index) {
      return {
        class: {
          headerRow: true,
        },
      };
    },
    customRow: function (record, index) {
      return {
        class: {
          isSelected: record.isSelected,
        },
        on: {
          //// 事件
          click: (event) => {
            event.stopPropagation();
            this.selectedRow = record.model;
            let node = event.target.closest('td');
            if (node) {
              this.clearSelectElements();
              this.selectIndex = [node.cellIndex];
              this.selectedRowIndex = record.model.cells[0].value;
              this.selectElements.push(node);
              node.classList.toggle('checkedCell');
              node.parentElement.children[0].classList.toggle('checkedNumber');
              console.log('record', record);
              this.arrowInit(event);
            }
          }, //// 点击行
          contextmenu: (event) => {
            event.preventDefault();
            this.selectedRow = record.model;
            let node = event.target.closest('td');
            if (!node) return;
            this.clearSelectElements();
            this.selectIndex = [node.cellIndex];
            this.selectElements.push(node);
            node.classList.toggle('checkedCell');
            node.parentElement.children[0].classList.toggle('checkedNumber');
            console.log('record', record);
            this.arrowInit(event);
            //// let model = this.selectedRow.umlDiagramElement.getModelElements().toArray()[0];
            //// let menu = tableUtil.GenerateRelationship(menuConfig, model);
            ContextMenu.popup({
              x: event.clientX,
              y: event.clientY,
              menuItems: menuConfig,
            })
              .then((menuItem) => {
                console.log('menuItem', menuItem);
                this[menuItem.method] && this[menuItem.method](event, menuItem);
              })
              .catch((err) => err && console.error(err));
          },
        },
      };
    },
    clickOuthandler: function () {
      this.selectIndex = [];
      this.selectedRow = null;
      this.clearSelectElements();
      this.arrowInit();
    },
    selectAllCell: function (e, record, rowIndex) {
      e.stopPropagation();
      e.preventDefault();
      this.clearSelectElements();
      this.selectIndex = 'all';
      this.selectedRow = record.model;
      let row = e.target.closest('tr');
      row.querySelectorAll('td').forEach((element) => {
        this.selectElements.push(element);
        element.classList.toggle('checkedCell');
      });
      this.arrowInit(e);
    },
    clearSelectElements() {
      if (this.selectElements.length > 0) {
        this.count = 0;
        this.selectElements.forEach((element) => {
          element.classList.remove('checkedCell');
          element.parentElement &&
						element.parentElement.children[0].classList.remove('checkedNumber');
        });
        this.selectElements = [];
      }
    },
    onChange: function (checkValue) {
      this.selectedColumnIds = checkValue;
      tableUtil.setColumnId(this.tableId, { columnIds: checkValue });
      this.updateTable();
    },
    showModelPostion: function () {
      let graphNode =  this.selectedRow.container;
      actions.getAction('selectOnTree').run(graphNode);

    },
    addRequirement: function (e, { level }) {
      const diagramNode = graphHelper.getGraphNodeById(this.tableId, app.activeProjectId);
      const typeName = 'Requirement';
      let umlShape = diagramNode.umlDiagramFrame;
      const addType = level;

      switch (level) {
        case 'tail':
          umlShape = diagramNode.umlDiagramFrame;
          break;
        case 'child':
          umlShape = this.selectedRow;
          break;
        case 'same':
          umlShape = this.selectedRow.owner;
          break;
      }
      //// console.log('umlShape', umlShape);
      const newName = this.getUniqueName(umlShape);
      const childrenShape = diagramNode.addRowElement(typeName, umlShape, addType, diagramNode.projectId)[0];      
      childrenShape.container.rowElement = childrenShape;
      this.initProperty(childrenShape.container, diagramNode);
      this.updateName(newName, diagramNode, childrenShape.container);
      this.updateTable(childrenShape.container);
    },

    //// 获取独立的name
    getUniqueName (shape) {
      const type = shape.getTypeName();
      let graphNode = null;
      if (type === 'RequirementTable') {
        graphNode = shape.container.container;
      } else {
        graphNode = shape.container;
      }
      //// console.log('graphNode', graphNode);
      const nameObj = {};
      this.searchTree(graphNode.children, 0, node => {
        if (node.getTypeName() === 'Requirement') {
          nameObj[node.name] = true;
        }
      });
      const newName = this.getName(0, nameObj);
      console.log('type', type, nameObj, newName);
      return newName;
      
      //// if (type === ) {}
    },

    updateName(name, rootNode, graphNode) {
      const properties = graphNode.properties.toArray();
      const propertiesObj = rootNode.propertyKeysObj;
      PropertyUtil.updateRow(name, properties[propertiesObj['名称']], graphNode);
    },

    initProperty: function (graphNode, rootNode) {
      GraphNodeUtil.initProperty(graphNode);
      const needSetPropertiesObj = !rootNode.propertyKeysObj;
      const properties = graphNode.properties.toArray();
      const propertiesObj = {};
      if (needSetPropertiesObj) {
        rootNode.propertyKeysObj = propertiesObj;
        properties.forEach((item, index) => {
        //// PropertyUtil.initPropertyConfig(item);
          if (needSetPropertiesObj) {
            propertiesObj[item.config.name] = index;
          }
        });
        //// 获取shape中的属性后, 以[key]:index形式存储在propertyKeysObj中
        rootNode.propertyKeysObj = propertiesObj;
      }
    },
    selectRequirement: function () {
      let currentIds = [];
      if (this.tableData.visibleRows.length > 0) {
        treeForEach(this.originData, (node) => {
          currentIds.push(node.modelElementId);
        });
      }
      
      selectMutiple
        .popup({
          type: 'Requirement',
          currentIds,
          filterCondtion: 'SysML::Requirements::AbstractRequirement',
          propertyKey: 'Not Exists PropertyKey',
          selectChildren: true,
        })
        .then((res) => {
          let rowElements = res.map((item) => item.graphNode);
          const diagramNode = graphHelper.getGraphNodeById(this.tableId, app.activeProjectId);
          diagramNode.addRowLeafs(rowElements, diagramNode.projectId);
          if (rowElements.length > 0 && !diagramNode.propertyKeysObj) {
            this.initProperty(rowElements[0], diagramNode);
          }
          this.updateTable();
        })
        .catch((e) => {
          e && console.error(e);
        });
    },
    move: function () {},
    deleteRequirement: function () {
      const graphNode = this.selectedRow.container;
      graphNode.remove();
      this.updateTable();
    },
    removeFromTable: function () {
      if (this.selectedRow != null) {
        //// tableUtil.removeFromTable(this.tableId, {
        ////   row: this.selectedRow,
        //// });
        this.selectedRow.remove();
        this.updateTable();
      }
    },
    hideColumn: function () {
      console.log('this.selectIndex', this.selectIndex);
      if (this.selectIndex.length > 0) {
        this.selectedColumnIds.splice(this.selectIndex[0] - 1, 1);
        this.onChange(this.selectedColumnIds);
      }
    },
    clearSearchValue: function () {
      this.searchValue = '';
      this.count = 0;
      this.searchResultVisible = false;
      this.clearSearchCell();
      this.clearSelectElements();
    },
    clearSelect() {
      this.selectIndex = [];
      this.selectElements = [];
    },
    clearSearchCell() {
      const tableContainer = this.$refs.tableContainer;
      if (tableContainer.querySelectorAll('.searchedCell').length > 0) {
        this.count = 0;
        tableContainer.querySelectorAll('.searchedCell').forEach((element) => {
          console.log('element', element);
          element.classList.remove('searchedCell');
          this.searchElements = [];
        });
      }
    },
    onSearch: function (searchValue) {
      this.clearSelectElements();
      this.clearSearchCell();
      this.count = 0;
      const allKeys = [];
      const searchRange = [];
      searchValue = searchValue.trim();
      if (searchValue.length > 100) {
        const option = {
          id: 110,
          text: '超出限制，输入内容请控制在1-100个字符内',
        };
        window.app.$messageBox.error(option);
        return;
      }

      let rows = this.$refs.table.querySelectorAll('.customRow');
      for (let i = 0; i < rows.length; i++) {
        let tds = rows[i].querySelectorAll('td');
        tds[0].classList.add('isFirst');

        if (this.selectedColumn === 'all') {
          for (let j = 0; j < tds.length; j++) {
            searchRange.push(tds[j]);
          }
        } else {
          let index;
          for (let j in this.columns) {
            if (this.selectedColumn === this.columns[j].key) {
              index = this.columns[j].index;
            }
          }
          if (index) {
            searchRange.push(tds[index]);
          }
        }
      }

      if (searchValue !== '' && searchRange.length > 0) {
        this.searchResultVisible = true;
        for (let i = 0; i < searchRange.length; i++) {
          if (searchRange[i].innerText.match(searchValue)) {
            this.count++;
            this.searchElements.push(searchRange[i]);
            searchRange[i].classList.add('searchedCell');
          }
        }
        this.nextOpacity = '1';
        this.previousOpacity = '0.3';
        if (this.count === 0) {
          this.nextOpacity = '0.3';
        } else {
          this.nextOpacity = '1';
        }
      }
    },

    arrowUpIn: function () {
      this.previousTipVisible = true;
    },
    arrowDownIn: function () {
      this.nextTipVisible = true;
    },
    arrowUpOut: function () {
      this.previousTipVisible = false;
    },
    arrowDownOut: function () {
      this.nextTipVisible = false;
    },
    arrowUpClick: function (e) {
      e.stopPropagation();
      if (this.searchElements.length > 0) {
        this.nextOpacity = '1';
        if (this.selectElements.length > 0) {
          let index = this.searchElements.indexOf(this.selectElements[0]);
          if (index > 0) {
            this.clearSelectElements();
            if (this.searchElements[index - 1].classList.contains('isFirst')) {
              let row = this.searchElements[index - 1].parentElement;
              row.querySelectorAll('td').forEach((element) => {
                element.classList.toggle('checkedCell');
                this.selectElements.push(element);
              });
            } else {
              this.searchElements[index - 1].classList.toggle('checkedCell');
              this.selectElements.push(this.searchElements[index - 1]);
            }
            if (index - 1 === 0) {
              this.previousOpacity = '0.3';
            }
          }
        }
      }
    },
    arrowDownClick: function (e) {
      e.stopPropagation();
      if (this.searchElements.length > 0) {
        if (this.selectElements.length > 0) {
          let index = this.searchElements.indexOf(this.selectElements[0]);
          if (index > -1 && index < this.searchElements.length - 1) {
            this.previousOpacity = '1';
            this.clearSelectElements();
            if (this.searchElements[index + 1].classList.contains('isFirst')) {
              let row = this.searchElements[index + 1].parentElement;
              row.querySelectorAll('td').forEach((element) => {
                this.selectElements.push(element);
                element.classList.toggle('checkedCell');
              });
            } else {
              this.searchElements[index + 1].classList.toggle('checkedCell');
              this.selectElements.push(this.searchElements[index + 1]);
            }
            if (index + 1 === this.searchElements.length - 1) {
              this.nextOpacity = '0.3';
            }
          }
        } else {
          this.previousOpacity = '0.3';
          if (this.searchElements[0].classList.contains('isFirst')) {
            let row = this.searchElements[0].parentElement;
            row.querySelectorAll('td').forEach((element) => {
              this.selectElements.push(element);
              element.classList.toggle('checkedCell');
            });
          } else {
            this.selectElements.push(this.searchElements[0]);
            this.searchElements[0].classList.toggle('checkedCell');
          }
        }
      }
    },
    arrowInit: function (event) {
      if (!event) {
        this.previousOpacity = '0.3';
        if (this.searchElements.length > 0) {
          this.nextOpacity = '1';
        } else {
          this.nextOpacity = '0.3';
        }
        return;
      }
      if (event.target === this.searchElements[this.searchElements.length - 1]) {
        this.nextOpacity = '0.3';
      } else {
        this.nextOpacity = '1';
      }
      if (
        event.target === this.searchElements[0] ||
				!this.searchElements.find((item) => item === event.target)
      ) {
        this.previousOpacity = '0.3';
      } else {
        this.previousOpacity = '1';
      }
    },
    contentDbclick(record, index, { editType, propsName }) {
      record[`${propsName}Editable`] = true;
      this.$set(this, 'originData', [...this.originData]);
      if (propsName !== 'ReqId') {
        this.$nextTick(() => {
          this.$refs.input[0].focus();
        });
      }
    },
    contentConfirm(e, record, index, { editType, propsName }) {
      if (
        editType === 'Name' &&
				(e.target.value.length === 0 || e.target.value.length > 50)
      ) {
        const option = {
          id: 110,
          text: '超出限制，输入内容请控制在1-50个字符内',
        };
        window.app.$messageBox.error(option);
        return;
      }
      if (editType === 'Text' && e.target.value.length > 1000) {
        const option = {
          id: 110,
          text: '超出限制，输入内容请控制在1000个字符内',
        };
        window.app.$messageBox.error(option);
        return;
      }
      if (
        editType === 'Name' ||
				(editType === 'Text' && e.target.value.length <= 1000)
      ) {
        const cell = record.model.cells[this.selectIndex[0]];
        if (this.judgeNameUnique(e.target.value, record.Name, record.model.container.container.children)) {
          this.$messageBox.warn({ text: '名称已重复' });
          record[`${propsName}Editable`] = false;
          return;
        }
        this.updateRow(cell, e.target.value);
        cell.value = e.target.value;
        record[editType] = e.target.value;
        record[`${propsName}Editable`] = false;
      }
    },

    //// 判断是否重名
    judgeNameUnique(name, oldName, graphNodes) {
      const nameObj = {};
      this.searchTree(graphNodes, 0, node => {
        if (node.getTypeName() === 'Requirement') {
          nameObj[node.name] = true;
          return false;
        }       
      });
      nameObj[oldName] = false;
      //// console.log('nameObj', graphNodes, nameObj[name]);
      return nameObj[name];
    },

    showTextAreaModal(text, record, index, { propsName, editType }) {
      textareaModal
        .popup({ content: text, type: editType })
        .then((res) => {
          const cell = record.model.cells[this.selectIndex[0]];
          console.log('record121', index, record);
          if (this.judgeNameUnique(res, record.Name, record.model.container.container.children)) {
            this.$messageBox.warn({ text: '名称已重复' });
            return;
          };
          this.updateRow(cell, res);
          cell.value = res;
          record[propsName] = res;
        })
        .catch((err) => err && console.error(err));
    },
    showAttribute(e, menuItem) {
      //// treeUtil.showAttribute();
      const action = actions.getAction(menuItem.method);
      console.log('action', action);
      if (!action) return;
      //// TODO
      action.onShapeMenuClick(null, this.selectedRow);
    },
    handleSingleSelect(record, rowIndex) {
      //// this.selectedRow = record.model;
      //// console.log('record', record, this.selectedRow);
      const selectColumnIndex = this.selectedColumnIds.length;
      if (this.inSelect) return;
      this.inSelect = true;
      let cell = record.model.cells[this.selectIndex[0]];

      let column = this.columns[this.selectIndex[0]];
      let selectModel = null;
      if (
        this.selectedRow != null &&
				this.selectedRow.umlDiagramElement.getModelElements().toArray().length > 0
      ) {
        selectModel = this.selectedRow.umlDiagramElement.getModelElements().toArray()[0];
      }
      selectValue
        .popup({
          currentId: cell.value && cell.value.id,
          propertyKey: column.key,
          selectedElement: selectModel,
          filterCondtion: 'SysML::Requirements::AbstractRequirement',
          isRequired: true
        })
        .then((res) => {
          console.log('cell, res.graphNode.model, [res.graphNode]', cell, res.graphNode.model, [res.graphNode]);
          this.updateRow(cell, res.graphNode.model, [res.graphNode]);
          this.updateTable();
        })
        .catch((e) => {
          e && console.error(e);
        })
        .finally((res) => {
          this.inSelect = false;
        });
    },
    handleMutiSelect(record) {
      if (this.inSelect) return;
      let cell = record.model.cells[this.selectIndex[0]];
      let column = this.columns[this.selectIndex[0]];
      this.inSelect = true;
      let selectModel = null;
      if (
        this.selectedRow != null &&
				this.selectedRow.umlDiagramElement.getModelElements().toArray().length > 0
      ) {
        selectModel = this.selectedRow.umlDiagramElement.getModelElements().toArray()[0];
      }
      selectMutiple
        .popup({
          currentIds:
						cell.value && Array.isArray(cell.value)
						  ? cell.value.map((i) => i.id)
						  : [],
          filterCondtion: column.moreBtnCondition,
          propertyKey: column.key,
          selectedElement: selectModel,
          selectChildren: true
        })
        .then((res) => {
          const modelArr = res.map((i) => i.graphNode.model);
          const graphNodes = res.map((i) => i.graphNode);
          this.updateRow(cell, modelArr, graphNodes);
          this.updateTable();
        })
        .catch((e) => {
          e && console.error(e);
        })
        .finally(() => {
          this.inSelect = false;
        });
    },
    //// 更新属性
    updateRow(cell, value, graphNodes) {
      const key = cell.name;
      console.log('key', cell);
      const diagramNode = graphHelper.getGraphNodeById(this.tableId, app.activeProjectId);
      const propertiesObj = diagramNode.propertyKeysObj;
      const graphNode = this.selectedRow.container;
      const properties = graphNode.properties.toArray();
      const currentProperty = properties[propertiesObj[key]];
      //// console.log(value, currentProperty, graphNode);
      PropertyUtil.updateRow(value, currentProperty, graphNode, graphNodes);
      this.$bus.emit('model-update', { id: app.selectedElement.model.id });
    },
    /* 出方向 */
    createOutgoing(event, data) {
      const action = actions.getAction('openCreateOutRelation');
      if (!action) return;
      action.onTreeMenuClick(this.selectedRow.container);
    },
    createIncoming(event, data) {
      const action = actions.getAction('openCreateInRelation');
      if (!action) return;
      action.onTreeMenuClick(this.selectedRow.container);
    },
    async incoming(model, item) {
      if (this.inSelectValue) return;
      this.inSelectValue = true;
      const res = await selectValue
        .popup({ selectedElement: app.ui.selectElement })
        .catch((err) => err && console.error(err));
      this.inSelectValue = false;
      if (res) {
        this.checkCreateRelation({
          source: res.model,
          target: model,
          keyName: item.value,
        });
      }
    },
    async outgoing(model, item) {
      if (this.inSelectValue) return;
      this.inSelectValue = true;
      const res = await selectValue
        .popup({ selectedElement: app.ui.selectElement })
        .catch((err) => err && console.error(err));
      this.inSelectValue = false;
      if (res) {
        this.checkCreateRelation({
          source: model,
          target: res.model,
          keyName: item.value,
        });
      }
    },
    checkCreateRelation({ source, target, keyName }) {
      let parent = SysMLUtilHelper.getRelationElementParent(
        keyName,
        source,
        target
      );
      const relationElement = SysMLUtilHelper.createRelationElementByNameType(
        keyName,
        source,
        source,
        target,
        null
      );

      if (!relationElement)
        console.error('create relation faild', { source, target, keyName });
      this.$bus.emit('model-add', { id: relationElement.getId() });
    },

    handleTreeDragMouseover(event) {
      event.preventDefault();
      //// event.dataTransfer.dropEffect = 'copy';

      this.handleTreeDragMouseover_(event);
    },
    handleTreeDragMouseover_(event) {
      if (!treeUtil.dragData) return;
      const model = treeUtil.dragData.model;
      //// const typeName = modelApi.getModelTypeName(model);
      const typeName = model.typeName;
      if (typeName === 'Requirement') {
        event.dataTransfer.dropEffect = 'copy';
      }
    },
    dragHandler() {
      console.log('triger drag', treeUtil.dragData);
      const dragData = treeUtil.dragData;
      if (!dragData) return;
      //// const typeName = modelApi.getModelTypeName(dragData.model);
      const typeName = dragData.model.typeName;
      if (typeName === 'Requirement') {
        this.addDiagramElementsToTable(dragData);
        this.updateTable();
      }
    },
    addDiagramElementsToTable(dragData) {
      const parentGraphNode = graphHelper.getGraphNodeById(this.tableId, app.activeProjectId);
      let currentIdObj = {};
      this.searchTree(parentGraphNode.umlDiagramFrame.children, 0, (node) => { //// 获取已经存在表中的需求ID
        currentIdObj[node.container.id] = true;
        return node.children;
      });
      this.searchTree([dragData], 0, (node) => {
        if (node.model && node.model.typeName === 'Requirement') {
          currentIdObj[node.id] = true;
          !this.defaultExpandedRowKeys.includes(node.container.id) &&
              this.defaultExpandedRowKeys.push(node.container.id);
          return node.children;
        }
        return false;
      });
      let rowElements = [];
      this.searchTree(app.sysmlModel.children, 0, (node) => {
        if (node.model && (node.model.typeName === 'Requirement' || node.model.typeName === 'Package')) {
          if (currentIdObj[node.id]) {
            rowElements.push(node);
          }
          return node.children;
        }
        return false;
      });
      parentGraphNode.addRowLeafs(rowElements, parentGraphNode.projectId);
      if (!parentGraphNode.propertyKeysObj) {
        this.initProperty(dragData, parentGraphNode);
      }
      //// tableUtil.setScopeByElement(this.tableId, { rowElements: [model] });
      //// const dragDataChildren = dragData.children;
      //// if (dragDataChildren.length !== 0) {
      ////   let diagramElementArr = dragDataChildren.filter(
      ////     (item) => item.model && item.model.typeName === 'Requirement'
      ////   );
      ////   if (diagramElementArr.length !== 0) {
      ////     diagramElementArr.forEach((item) => {
      ////       this.addDiagramElementsToTable(item, dragData);
      ////     });
      ////   }
      //// }
    },
    //// 导入
    async importRequirementTableExcel() {
      if (!storage.get('notTip-importTable-excel') && globalConfig.isElectron) {
        const fs = require('fs');
        const path = require('path');
        const appPath = process.cwd();
        const result = await app.$Confirm
          .popup({
            title: '提示',
            subTitle: '导入Excel',
            content: '系统只读取Excel的id, name, text字段。',
            subContent: '导入后将生成新的需求表和需求放在独立的包内。',
            showCheckbox: true,
            checkboxText: '不再提示',
            status: 'warn',
            centerBtnText: '',
            cancelText: '下载模板',
            onClickCancel: () => {
              const filePath = LocalFile.showSaveDialog({
                title: '下载模板',
                defaultPath: path.resolve(appPath, './需求表导入模板.xlsx'),
                filters: [{ name: 'M-Design', extensions: ['xlsx'] }],
              });
              if (!filePath) return;
              const sourceFilePath = path.resolve(
                appPath,
                './files/需求表导入模板.xlsx'
              );
              fs.copyFileSync(sourceFilePath, filePath);
              this.$message.success('下载成功');
            },
          })
          .catch((e) => {
            e && console.error(e);
            return false;
          });
        if (!result) return;
        if (result.checked) {
          storage.set('notTip-importTable-excel', true);
        }
      }
      LocalFile.openExcel().then((res) => {
        console.log('res', res);
        if (!res) return;
        //// 解析数据
        const { data, name } = res;
        const workbook = XLSX.read(data, {
          type: 'buffer',
          cellHTML: false,
        });
        const sheetNames = workbook.SheetNames;
        //// 根据表名获取对应某张表
        const worksheet = workbook.Sheets[sheetNames[0]];
        const sheetjson = XLSX.utils.sheet_to_json(worksheet);
        const requirements = [];
        sheetjson.forEach((item) => {
          if (!item || !item['名称']) return;
          let id = item['序号'];
          if (id === undefined || id === null) {
            id = '';
          } else {
            id = id + '';
          }
          requirements.push({
            id,
            name: item['名称'] || '',
            text: item['描述'] || '',
          });
        });
        console.log('000000000000000000', requirements);
        const diagramNode = graphHelper.getGraphNodeById(this.tableId, app.activeProjectId);
        app.sysmlModel.importExcel(requirements);
        //// const packageModel = SysMLUtilHelper.importExcel(
        ////   requirements,
        ////   app.sysmlModel
        //// );
        //// let nameList = packageModel
        ////   .getOwner()
        ////   .getOwnedElements()
        ////   .toArray()
        ////   .filter((i) => i !== packageModel)
        ////   .map((model) => model.getName());
        //// const uniqueName = getUniqueName(nameList, name);
        //// SysMLUtilHelper.updateName(uniqueName, packageModel);
        //// const tabelDiagram = packageModel.diagramElement.toArray()[0];
        //// if (tabelDiagram) {
        ////   SysMLUtilHelper.updateName(name, tabelDiagram);
        //// }
        //// this.renameImportRequirement(packageModel);
        //// console.log(packageModel);
        //// this.$bus.emit('model-add', { id: packageModel.getId() });
      });
    },
    async importRequirementTableReqif() {
      if (!storage.get('notTip-importTable-reqif')) {
        const fs = require('fs');
        const path = require('path');
        const appPath = process.cwd();
        const result = await app.$Confirm
          .popup({
            title: '提示',
            subTitle: '导入ReqIF',
            content: '系统只读取ReqIF.ID, ReqIF.Name, ReqIF.Text字段。',
            subContent: '导入后将生成新的需求表和需求放在独立的包内。',
            showCheckbox: true,
            checkboxText: '不再提示',
            status: 'warn',
            cancelText: '下载模板',
            onClickCancel: () => {
              const filePath = LocalFile.showSaveDialog({
                title: '下载模板',
                defaultPath: path.resolve(appPath, './需求表导入模板.reqif'),
                filters: [{ name: 'M-Design', extensions: ['reqif'] }],
              });
              if (!filePath) return;
              const sourceFilePath = path.resolve(
                appPath,
                './files/需求表导入模板.reqif'
              );
              fs.copyFileSync(sourceFilePath, filePath);
              this.$message.success('下载成功');
            },
          })
          .catch(() => false);
        if (!result) return;
        if (result.checked) {
          storage.set('notTip-importTable-reqif', true);
        }
      }
      LocalFile.openReqif().then((res) => {
        if (!res) return;
        const { data, name } = res;
        const options = {
          mergeCDATA: false,
          xmlns: false,
          attrsAsObject: false,
          childrenAsArray: false,
          ignoreAttributes: false,
          parseAttributeValue: true,
          attributeNamePrefix: '',
        };
        const diagram = app.selectedElement;
        const str = data.toString();
        const result = xmlParser.parse(str, options);
        console.log(result);
        parseDataToReqif(result);
        console.log(result);
        const jsonStr = JSON.stringify(result);

        //// const result = JSON.stringify(XmlToJson.parseString(data, options));
        const packageModel = SysMLUtilHelper.importReqIfToRequirement(
          SysMLUtilHelper.deSerReqIf(jsonStr),
          app.sysmlModel
        );

        let nameList = packageModel
          .getOwner()
          .getOwnedElements()
          .toArray()
          .map((model) => model.getName());
        const uniqueName = getUniqueName(nameList, name);
        SysMLUtilHelper.updateName(uniqueName, packageModel);
        const tabelDiagram = packageModel.diagramElement.toArray()[0];
        if (tabelDiagram) {
          SysMLUtilHelper.updateName(name, tabelDiagram);
        }
        this.renameImportRequirement(packageModel);
        console.log(packageModel);
        this.$bus.emit('model-add', { id: packageModel.getId() });
        //// res.getOwnedMembers().toArray().filter(item => SysMLUtilHelper.isRequirement(item)).forEach(item => {
        ////   this.addToTable(item, diagram);
        //// });
        //// this.$bus.emit('model-add', { id: res.getId() });
        //// this.$bus.emit('model-update', { id: diagram.getId() });
      });
    },
    renameImportRequirement(packageModel) {
      const ownedElements = packageModel.getOwnedElements().toArray();
      ownedElements.forEach((item) => {
        const nameList = ownedElements
          .filter((it) => it !== item)
          .map((item) => item.getName());
        const newName = getUniqueName(nameList, item.getName() || '未命名');
        if (newName !== item.getName()) {
          SysMLUtilHelper.updateName(newName, item);
        }
        if (item.getOwnedElements().size) {
          this.renameImportRequirement(item);
        }
      });
    },
    exportRequireTableExcel() {
      const diagram = graphHelper.getGraphNodeById(this.tableId, app.activeProjectId);

      const farmatter = {
        Id: '序号',
        Text: '描述',
        RefinedBy: '被精化',
        TracedTo: '追溯',
        SatisfiedBy: '被满足',
        Derived: '被源于',
        DerivedFrom: '源于',
        VerifiedBy: '被验证',
      };
      console.log('diagram', diagram);
      LocalFile.exportRequirementTableExcel(this.tableData, diagram.getName(), farmatter).then(text => {
        this.$messageBox.success({ text });
      });
    },
    exportRequirementTableReqif() {
      const diagram = graphHelper.getGraphNodeById(this.tableId, app.activeProjectId).model;
      return this.$messageBox.warn({ text: '暂未提供该功能' });
      //// LocalFile.exportRequirementTableReqif(this.tableData, diagram.getName());    
    },

    //// 自定义展开图标
    changeExpandIcon(props) {
      //// console.log('props', props);
      const expanded = props.expanded;
      const expandable = props.expandable;
      if (props.record.children) {
        if (props.expanded) { //// 有数据-展开时候图标
          return (
            <div class="_rect" 
              onClick={(e) => {
                props.onExpand(props.record, e);
              }}>
              <div class="_rect-1"></div>
            </div>
          );
        } else { //// 有数据-未展开时候图标
          return (
            <div class="_rect" 
              onClick={(e) => {
                props.onExpand(props.record, e);
              }}>
              <div class="_rect-1"></div>
              <div class="_rect-2"></div>
            </div>
          );
        }
      } else { //// 无数据-图标
        return <div style="display: inline-block; width: 17px"></div>;
      }
    },

    handleZoomSmall() {
      if (this.scale <= 10) return;
      if (this.scale < 20) {
        this.scale = 10;
      } else {
        this.scale -= 10;
      }
      //// this.ui.editor.graph.zoomTo(this.scale / 100);
    },
    handleZoomLarge() {
      if (this.scale >= 1000) return;
      if (this.scale >= 900) {
        this.scale = 1000;
      } else {
        this.scale += 10;
      }
      //// this.ui.editor.graph.zoomTo(this.scale / 100);
    },
    //// 点击上移
    upMove(){
      app.$messageBox.warn({
      //// id: 100,
        text: '功能开发中，敬请期待',
        title: '试用版'
      });
    },
    //// 点击下移
    downMove(){
      app.$messageBox.warn({
      //// id: 100,
        text: '功能开发中，敬请期待',
        title: '试用版'
      });
    },
    //// 点击图例
    legendClick(){
      app.$messageBox.warn({
      //// id: 100,
        text: '功能开发中，敬请期待',
        title: '试用版'
      });
    }
  },
};
</script>
<style lang="scss">
.tableContainer {
	height: 100%;
	width: 100%;
	background: linear-gradient(360deg, #f7f6f6 0%, #f8f8f8 100%);
  .ant-table {
    display: inline-block;
    .addModal {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      right: 5px;
    }
  }
  ._rect {
    margin-right: 6px;
    cursor: pointer;
    width: 11px;
    height: 11px;
    box-sizing: border-box;
    border: 1px solid black;
    position: relative;
    display: inline-block;
    background: white;
    margin-bottom: 1px;
    top: 2px;
    ._rect-1 {
      position: absolute;
      width: 5px;
      border-top: 1px solid black;
      left: 2px;
      top: 4px;

    }
    ._rect-2 {
      position: absolute;
      height: 5px;
      border-left: 1px solid black;
      left: 4px;
      top: 2px;

    }
  }
	._table {
		height: calc(100% - 72px);
		overflow: auto;
    margin-left: 4px;
		width: calc(100vw - 420px);
		.ant-table-wrapper {
      width: 99%;
      margin-left:10px;
		}
	}
	.customRow {
		background-color: #ffffff;
	}

	.ant-table-row-cell-break-word {
		&.ReqId {
			span:last-child {
				opacity: 0.25;
			}
		}
	}

	.textCell {
		white-space: break-spaces;
    position: relative;
		&.Name {
			.div_input,
			input {
				vertical-align: top;
				display: inline-block;
				overflow: hidden;
				text-overflow: ellipsis;
				white-space: nowrap;
				width: calc(90% - 10px);
			}
		}
	}
	.toolbar {
		width: 100%;
		height: 28px;
		line-height: 28px;
		padding-left: 4px;
		display: inline-flex;
		flex-direction: row;
		align-items: center;
		background: #d4ebf8;
		border-bottom: 1px solid #99b1c5;
		.toolbarDiv {
			display: flex;
			height: 28px;
			line-height: 28px;
			align-items: center;
		}
		.toolbarItem {
			display: flex;
			height: 24px;
			line-height: 24px;
			margin-left: 12px;
			font-size: 12px;
			cursor: pointer;
			&.disabled {
				opacity: 0.25;
				cursor: not-allowed;
			}
      ._dropdown {
        &.disabled {
				opacity: 0.25;
				cursor: not-allowed;
			}
      }
			&:hover {
				background: linear-gradient(107deg, #a3dbff 0%, #74c5f8 100%);
				border: 1px solid #b1cee2;
			}
			.itemContent {
				display: flex;
				align-items: center;
				text-align: center;
				height: 24px;
        line-height: 24px;
				._top-btn {
					._btn-img {
						margin-top: -2px;
					}
				}
				.scale {
					margin: 0 4px;
				}
			}
			.des {
				margin-left: 4px;
			}
		}
		.icon {
			height: 16px;
			width: 16px;
			margin: 4px 2px;
			display: inline-block;
			vertical-align: middle;
			background-size: 16px 16px;
			background-repeat: no-repeat;
			&.icon_showModelPosition {
				background-image: url('../../../public/statics/icons/table/showModelPosition.svg');
			}
			//// &.icon_requirementField{
			////   background-image: url('../../../public/statics/icons/table/requirementField.svg');
			//// }
			&.icon_requirementField {
				background-image: url('../../../public/statics/images/mainpage/iconchoose.svg');
			}
			&.icon_addRequirement {
				background-image: url('../../../public/statics/icons/table/addRequirement.svg');
			}
			&.icon_selectRequirement {
				background-image: url('../../../public/statics/icons/table/selectRequirement.svg');
			}
			&.icon_deleteRequirement {
				background-image: url('../../../public/statics/icons/table/deleteRequirement.svg');
			}
			&.icon_removeFromTable {
				background-image: url('../../../public/statics/icons/table/removeFromTable.svg');
			}
			&.icon_recall {
				background-image: url('../../../public/statics/icons/app/toolbarrecall.svg');
			}
			&.icon_redo {
				background-image: url('../../../public/statics/icons/app/toolbarredo.svg');
			}
			&.icon_iconMovedown {
				background-image: url('../../../public/statics/icons/table/iconMovedown.svg');
			}
			&.icon_iconMoveup {
				background-image: url('../../../public/statics/icons/table/iconMoveup.svg');
			}
			&.icon_iconLegend {
				background-image: url('../../../public/statics/icons/table/iconLegend.svg');
			}
			&.icon_iconleadin {
				background-image: url('../../../public/statics/icons/table/iconleadin.svg');
			}
			&.icon_iconexport {
				background-image: url('../../../public/statics/icons/table/iconexport.svg');
			}
			&.icon_toolbarreduce {
				background-image: url('../../../public/statics/icons/app/toolbarreduce.svg');
			}
			&.icon_toolbarenlarge {
				background-image: url('../../../public/statics/icons/app/toolbarenlarge.svg');
			}
			&.icon_topiconline {
				background-image: url('../../../public/statics/images/mainpage/topiconline.svg');
			}
		}
		.icon_topiconline {
			width: 1px;
			height: 25px;
			line-height: 32px;
			margin-left: 8px;
			border: 1px solid #b1cee2;
		}
		.iconbarline {
			margin-left: 8px;
		}
	}

	.allTable {
		overflow-y: auto;
		height: calc(100% - 75px);
	}
	.searchBar {
		height: 42px;
		background: #fafafa;
		padding-top: 9px;
		padding-bottom: 9px;
		padding-left: 15px;
		font-size: 12px;
		> * {
			vertical-align: middle;
		}
		> span {
			margin-right: 8px;
		}
		._select {
			width: 100px;
			height: 26px;
			margin-right: 8px;
			.ant-select-selection--single {
				height: 26px;
				.ant-select-selection__rendered {
					line-height: 24px !important;
					font-size: 12px;
				}
			}
		}
		._input {
			display: inline-block;
			width: 180px;
			.ant-input {
				height: 26px;
			}
			.ant-input-search-button {
				height: 26px;
				color: #44525b;
				background: linear-gradient(
					180deg,
					#e5f6ff 0%,
					#c8e3f3 100%,
					#cae4f3 100%,
					#abd7ef 100%
				);
				border-radius: 0px;
				border: 1px solid #b1cee2;
			}
		}
		.previous {
			margin-right: 8px;
			cursor: pointer;
		}
		.next {
			cursor: pointer;
		}
		.previousTip {
			position: relative;
			float: left;
			left: 400px;
			top: 30px;
			z-index: 99;
		}
		.nextTip {
			position: relative;
			float: left;
			left: 420px;
			top: 30px;
			z-index: 99;
		}
		.triangle {
			position: absolute;
			left: 20px;
			width: 0;
			height: 0;
			border-style: solid;
			border-width: 5px;
			border-color: transparent transparent #434343 transparent;
		}
		.rectangle {
			position: absolute;
			width: 50px;
			height: 22px;
			background: #434343;
			box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.32);
			border-radius: 0px;
			font-size: 12px;
			color: #ffffff;
			line-height: 22px;
			text-align: center;
		}
	}
	._dropdown {
		height: 24px;
	}
	.anticon-edit,
	.iconAdd {
		visibility: hidden;
	}
	.checkedCell {
		//// max-width: 184px;
		background: #3483b8 !important;
		span {
			color: white;
		}
		.anticon-edit,
		.iconAdd {
			visibility: visible;
		}
		.div_input {
			color: white;
		}
	}
	.checkedNumber {
		background: #ecebeb !important;
	}
	.isSelected {
		color: white;
		background: #3483b8 !important;
		&:hover {
			background: #3483b8 !important;
		}
		td {
			background: #3483b8 !important;
			&:hover {
				background: #3483b8 !important;
			}
		}
	}
	.headerRow {
		> th {
			border-radius: 0px;
      &:last-of-type {
        border-right: none;
      }
		}
	}
	.headerRowCell {
		background: linear-gradient(
			180deg,
			#ffffff 0%,
			#e8e6e6 0%,
			#e4e4e4 97%,
			#868585 100%
		) !important;
		box-shadow: -2px 2px 0px 0px #ffffff, -2px 0px 0px 0px #c5c5c5;
		filter: blur(0px);
	}
	.searchedCell {
		background: linear-gradient(
			180deg,
			#e5f6ff 0%,
			#c8e3f3 100%,
			#cae4f3 100%,
			#abd7ef 100%
		);
	}
	.resize-table-th {
    position: relative;
    font-size:12px;
	}
	.table-draggable-handle {
		/* width: 10px !important; */
		height: 100% !important;
		left: auto !important;
		right: -5px;
		cursor: col-resize;
		touch-action: none;
		border: none;
		transform: none !important;
		position: absolute;
		top: 0;
	}
	.ant-table.ant-table-empty .ant-table-body {
		overflow: hidden !important;
	}
	.ant-table-small > .ant-table-content > div.ant-table-body {
		margin: 0px;
	}
	.checkListMenu {
		.ant-checkbox-group {
      font-size: 12px;
			display: flex;
			flex-direction: column;
			padding: 4px;
			label.ant-checkbox-wrapper {
        font-size: 12px;
				margin-left: 4px;
				&:hover {
					background: linear-gradient(
						180deg,
						#e7f5fe 0%,
						#b0deff 65%,
						#b2ddfd 100%
					);
				}
			}
		}
	}
	.buttonListMenu {
		.ant-dropdown-menu-item {
			//// height:24px;
			//// line-height: 24px;
			padding-left: 15px;
			&:hover {
				background: linear-gradient(
					180deg,
					#e7f5fe 0%,
					#b0deff 65%,
					#b2ddfd 100%
				);
			}
		}
	}
}
</style>
